package service

import (
	"a-common/alog"
	"a-common/config"
	"a-common/constant"
	"a-common/core/redis"
	"a-common/domain"
	"a-common/myerr"
	"a-common/utils/excel"
	"a-common/utils/ipaddr"
	"a-system/domain/pojo"
	"encoding/json"
	"fmt"
	"log/slog"
	"sync"
	"time"

	"github.com/gofiber/fiber/v2"
	"github.com/tidwall/gjson"
	"github.com/xuri/excelize/v2"
)

var (
	logininforServiceTemp *LogininforService
	logininforServiceOnce sync.Once
)

type LogininforService struct{}

func NewSysLogininforService() *LogininforService {
	logininforServiceOnce.Do(func() {
		logininforServiceTemp = &LogininforService{}
	})
	return logininforServiceTemp
}

// List 分页
func (m *LogininforService) List(args *pojo.SysLogininforDto) (vPage domain.PageVo, err error) {
	var timestampNow int64
	var timestampOneMonthAgo int64
	if args.Params.BeginTime != "" && args.Params.EndTime != "" {
		const layout = "2006-01-02 15:04:05"
		loc, err := time.LoadLocation("Asia/Shanghai")
		if err != nil {
			return vPage, err
		}
		begin, err := time.ParseInLocation(layout, args.Params.BeginTime, loc)
		if err != nil {
			return vPage, err
		}
		timestampOneMonthAgo = begin.UnixMicro()
		end, err := time.ParseInLocation(layout, args.Params.EndTime, loc)
		if err != nil {
			return vPage, err
		}
		timestampNow = end.UnixMicro()
	} else {
		// 获取当前时间
		now := time.Now()
		// 获取当前时间的时间戳，单位为微秒
		timestampNow = now.UnixNano() / int64(time.Microsecond)
		// 获取一个月前的时间
		oneMonthAgo := now.AddDate(0, -1, 0)
		// 获取一个月前的时间戳，单位为微秒
		timestampOneMonthAgo = oneMonthAgo.UnixNano() / int64(time.Microsecond)
	}

	index := config.Config.Openobserve.Index
	sqlStr := fmt.Sprintf("SELECT * FROM %s WHERE logtype='logininfor' ", index)
	if args.UserType != "" {
		sqlStr = sqlStr + "AND data_usertype='" + args.UserType + "' "
	}
	sqlStr = sqlStr + "ORDER BY _timestamp DESC"
	query := fmt.Sprintf(`{
		"query": {
			"sql": "%s",
			"start_time": %d,
			"end_time": %d,
			"from": %d,
			"size": %d,
			"track_total_hits": true
		},
		"timeout": 0
	}`, sqlStr, timestampOneMonthAgo, timestampNow, (args.PageNum-1)*args.PageSize, args.PageSize)
	vPage.PageNum = args.PageNum
	vPage.PageSize = args.PageSize

	resByte, err := alog.SendPost("_search", query)
	if err != nil {
		return vPage, err
	}
	if !gjson.ValidBytes(resByte) {
		return vPage, nil
	}
	resStr := string(resByte)
	rows := gjson.Get(resStr, "hits").Raw
	var result []map[string]any
	// 解码JSON到map
	err = json.Unmarshal([]byte(rows), &result)
	if err != nil {
		return vPage, err
	}

	for _, item := range result {
		if item["data_token"] != nil {
			keyExists, _ := redis.New().Exists(constant.LOGIN_SESSION + item["data_token"].(string))
			if keyExists > 0 {
				item["data_online"] = true
			} else {
				item["data_online"] = false
			}
		} else {
			item["data_online"] = false
		}
	}

	vPage.Rows = result
	vPage.Total = gjson.Get(resStr, "total").Int()
	return vPage, nil
}

// Export 导出
func (m *LogininforService) Export(args *pojo.SysLogininforDto) (file *excelize.File, err error) {
	vPage, err := m.List(args)
	if err != nil {
		return nil, err
	}
	return excel.NormalDynamicExport(vPage.Rows, "Sheet1", "登陆日志表", "", true, false, map[string]string{})
}

// Add 增
func (m *LogininforService) Add(ip, userName, userType, browserName, browserVersion, osName, osVersion, token string, err error) {
	msg := "successful"
	if err != nil {
		msg = err.Error()
	}
	// 添加登陆日志
	var info pojo.SysLogininfor
	info.UserName = userName
	info.UserType = userType
	info.Ipaddr = ip
	info.LoginLocation = ipaddr.New().GetRealAddressByIP(ip)
	info.Browser = browserName + " " + browserVersion
	info.Os = osName + " " + osVersion
	info.Token = token
	if err != nil {
		info.Status = myerr.CODE_405
	} else {
		info.Status = 200
	}
	info.Msg = msg
	slog.Info("登陆日志", slog.Any("data", info), slog.String("logType", "logininfor"))
}

// Clear 清空
func (m *LogininforService) Clear(c *fiber.Ctx) error {
	return nil
}

// Unlock 解锁
func (m *LogininforService) Unlock(userName string) error {
	// if err := global.RdCli.Del(constant.PWD_ERR_CNT_KEY + userName); err != nil {
	// 	return res.ServerFail(c, res.SYS_ERR_REDIS, err)
	// }
	return nil
}
